package org.coding.springbootdemowebsocket.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * @auth guoxh
 * @date 2020/10/17 9:52 上午
 * @desc Java NIO
 **/
public class MyServer {
    private int size = 1024;
    private ServerSocketChannel serverSocketChannel;
    private ByteBuffer byteBuffer;
    private Selector selector;
    private int remoteClientNum = 0;

    public MyServer(int port){
        try {
            initChannel(port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //channel 初始化
    public void initChannel(int port) throws IOException {
        //打开channel
        serverSocketChannel = ServerSocketChannel.open();
        //设置为非阻塞模式
        serverSocketChannel.configureBlocking(false);
        //绑定端口
        serverSocketChannel.bind(new InetSocketAddress(port));
        System.out.println("listener on port :" + port);
        //创建选择器
        selector = Selector.open();
        //向选择器注册通道
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        //分配缓冲区大小
        byteBuffer = ByteBuffer.allocate(size);
    }

    private void listener() throws IOException {
        while (true){
            int n = selector.select();
            if(n ==0){
                continue;
            }
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();

                if(key.isAcceptable()){
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                    SocketChannel channel = serverSocketChannel.accept();
                    registerChannel(selector,channel,SelectionKey.OP_READ);
                    remoteClientNum ++;
                    System.out.println("online client num :" + remoteClientNum);
                    write(channel,"hello world!".getBytes());
                }
                if(key.isReadable()){
                    read(key);
                }
            }

            iterator.remove();
        }
    }
    private void read(SelectionKey key) throws IOException {
        SocketChannel socketChannel = (SocketChannel) key.channel();
        int count = 0;
        byteBuffer.clear();
        while((count = socketChannel.read(byteBuffer)) >0){
            byteBuffer.flip();
            while(byteBuffer.hasRemaining()){
                System.out.println((char)byteBuffer.get());
            }
            byteBuffer.clear();
        }
        if(count < 0){
            serverSocketChannel.close();
        }

    }
    private void write(SocketChannel socketChannel,byte[] writeData) throws IOException {
        byteBuffer.clear();
        byteBuffer.put(writeData);
        byteBuffer.flip();
        socketChannel.write(byteBuffer);
    }

    private void registerChannel(Selector selector,SocketChannel socketChannel,int opRead) throws IOException {
        if(socketChannel == null){
            return;
        }
        socketChannel.configureBlocking(false);
        socketChannel.register(selector,opRead);
    }

    public static void main(String[] args) {
        MyServer myServer = new MyServer(9999);
        try {
            myServer.listener();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
